<?php

namespace App\Jobs;

use App\Models\Common\Constant;
use App\Models\Invoice\Invoice;
use App\Models\Invoice\Platform\ChinaUms;
use App\Models\Invoice\Subject;
use Carbon\Carbon;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Psr\Log\LoggerInterface;

class IssueInvoice implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    protected $order;
    protected $source;
    protected $invoiceTitle;

    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct(Model $order, array $invoiceTitle, string $source = Constant::SOURCE_ADMIN)
    {
        $this->order = $order;
        $this->invoiceTitle = $invoiceTitle;
        $this->source = $source;
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        $order = $this->order;
        $invoiceTitle = $this->invoiceTitle;
        $exceptionContent = "订单({$order->order_title}:{$order->order_code}])开具发票失败:";

        $order = $order->refresh();
        $lstInvoice = Invoice::where('parking_lot_id', $order->parking_lot_id)->where('paid_code', $order->paid_code)->where('status', Invoice::STATUS_SUCCESS)->orderBy('updated_at', 'DESC')->first();

        switch (optional($lstInvoice)->type) {
            case Invoice::TYPE_ISSUED:
                throw new \Exception($exceptionContent . '已有开票记录不可重复开票');
            case Invoice::TYPE_REVERSED:
                throw new \Exception($exceptionContent . '不支持换票逻辑');
            default:
                $invoice = Invoice::create([
                    'parking_lot_id' => $order->parking_lot_id,
                    'related_id' => $order->id,
                    'related_code' => $order->order_code,
                    'paid_code' => $order->paid_code,
                    'related_type' => get_class($order),
                    'source' => $this->source,
                    'app_user_id' => strval($order->app_user_id),
                    'type' => Invoice::TYPE_ISSUED,
                    'tag' => 1,
                    'status' => Invoice::STATUS_CREATE
                ]);
                break;
        }

        try {

            if (!$invoice) {
                throw new \Exception($exceptionContent . '生成开票记录失败');
            }

            if (!$subject = Subject::where('parking_lot_id', $order->parking_lot_id)->where('enabled', true)->first()) {
                throw new \Exception($exceptionContent . '车场未配置可用的开票主体');
            }

            if ($order->refund_amount) {
                throw new \Exception($exceptionContent . '订单已经退款记录');
            }

            if ($order->final_amount < 1) {
                throw new \Exception($exceptionContent . '订单实付金额小于0.01元');
            }

            if ($order->order_status !== Constant::ORDER_STATUS_PAID) {
                throw new \Exception($exceptionContent . '订单支付状态不为已支付');
            }

            switch ($subject->type) {
                case Subject::TYPE_CHINA_UMS:
                default:
                    $chinaUms = new ChinaUms($subject);
                    $chinaUms->heartBeat()->fire();
                    $response = $chinaUms->issuance([
                        'order_code' => $order->order_code,
                        'amount' => $order->final_amount,
                        'buyerName' => \Arr::get($invoiceTitle, 'title'),
                        'buyerTaxCode' => \Arr::get($invoiceTitle, 'tax_code'),
                        'buyerAddress' => \Arr::get($invoiceTitle, 'address'),
                        'buyerTelephone' => \Arr::get($invoiceTitle, 'phone'),
                        'buyerAccount' => \Arr::get($invoiceTitle, 'bank_account'),
                        'buyerBank' => '',//开户银行
                        'buyerBrevityCode' => '',//买方简码
                        'buyerGroupBrevityCode' => '',//买方集团简码
                        'paid_at' => $order->paid_at,
                        'goodsDetail' => $chinaUms->getGoodDetails($order)
                    ])->fire();

                    $resultCode = \Arr::get($response, 'resultCode');
                    $errMsg = \Arr::get($response, 'errMsg');
                    $status = \Arr::get($response, 'status');

                    if (!in_array($status, [ChinaUms::STATUS_ISSUED, ChinaUms::STATUS_ISSUING], true)) {
                        throw new \Exception($exceptionContent . '发票的状态不是已开具状态(' . $status . ')');
                    }

                    if ($resultCode === 'SUCCESS') {

                        $invoice->xml_dat = [
                            'xml' => strval(\Arr::get($response, 'xml')),
                            'preview_url' => strval(\Arr::get($response, 'xmlPreviewUrl')),
                            'url' => strval(\Arr::get($response, 'xmlUrl'))
                        ];

                        $invoice->pdf_dat = [
                            'pdf' => strval(\Arr::get($response, 'pdf')),
                            'preview_url' => strval(\Arr::get($response, 'pdfPreviewUrl')),
                            'url' => strval(\Arr::get($response, 'pdfUrl'))
                        ];

                        $invoice->ofd_dat = [
                            'ofd' => strval(\Arr::get($response, 'ofd')),
                            'preview_url' => strval(\Arr::get($response, 'ofdPreviewUrl')),
                            'url' => strval(\Arr::get($response, 'ofdUrl'))
                        ];

                        $invoice->qr_code_dat = [
                            'qr_code' => strval(\Arr::get($response, 'qrCodeId')),
                            'preview_url' => strval(\Arr::get($response, 'qrCode')),
                            'url' => strval(\Arr::get($response, 'issueQrCode'))
                        ];

                        $invoice->amount = floatval(\Arr::get($response, 'totalPrice'));
                        $invoice->total_amount = floatval(\Arr::get($response, 'totalPriceIncludingTax'));
                        $invoice->tax_amount = floatval(\Arr::get($response, 'totalTax'));

                        try {
                            $issueDate = Carbon::parse(\Arr::get($response, 'issueDate'))->toDateTimeString();
                        } catch (\Throwable $exception) {
                            $issueDate = now()->toDateTimeString();
                        }
                        $invoice->triggered_at = $issueDate;
                        $invoice->cipher_code = strval(\Arr::get($response, 'cipherCode'));
                        $invoice->check_code = strval(\Arr::get($response, 'checkCode'));
                        $invoice->good_details = @json_decode(strval(\Arr::get($response, 'goodsDetail')), true) ?: [];
                        $invoice->code = strval(\Arr::get($response, 'invoiceCode'));
                        $invoice->number = strval(\Arr::get($response, 'invoiceNo'));
                        $invoice->status = Invoice::STATUS_SUCCESS;
                    } else {
                        $invoice->err_msg = $errMsg;
                        $invoice->status = Invoice::STATUS_FAILED;
                    }
                    $invoice->save();
                    break;
            }
        } catch (\Throwable $exception) {
            $invoice->err_msg = $exception->getMessage();
            $invoice->status = Invoice::STATUS_FAILED;
            $invoice->save();
            app(LoggerInterface::class)->error($exception->getMessage(), ['exception' => $exception->getMessage(), 'trigger' => '开具发票脚本']);
        }
    }
}
